【React 19】サクッと理解するuseActionState
こんにちは、戸田です。
(2024/10/11 現在) React19 がメジャーバージョンになる前に新機能の useActionState について理解を深めようと思ったのでまとめました。
公式ドキュメント
useActionState の詳細と使い方
React 19 で導入されるuseActionState
は、フォームアクションの結果に基づいてステートを更新するためのフックです。このフックを使用することで、非同期アクションの状態管理が簡素化され、特にフォーム処理においてとても便利です。
useActionState とは
useActionState
は以下の特徴を持つフックです:
- フォームアクションの結果に基づいてステートを更新する
- 非同期アクションの実行状態(isPending)、成功時・エラー時の状態(state)を一元管理する
- Server Components 環境下('use server'を使用している時)では、JavaScript が実行される前にフォームを操作可能にする
基本的な使い方
const [state, formAction, isPending] = useActionState(action, initialState, permalink?);
action
: フォーム送信時に呼び出される関数initialState
: ステートの初期値permalink
: (オプション)ユニークなページ URL を含む文字列
permalink は最初の段階で理解する必要はないかと思います。
返り値:
state
: 現在のステートformAction
: フォームのaction
プロパティに渡すアクションisPending
: アクションが実行中かどうかを示すブール値(useTransition と同じ)
具体的な実装例
import { useActionState } from "react";
// ログインフォームの状態を定義する型
type LoginFormStateType = {
success: boolean;
};
// ログイン処理をシミュレートする非同期関数
const fetchLogin = async (name, password): Promise<LoginFormStateType> => {
// ここで認証をする(今回は通信時間を3秒として模倣)
await new Promise((resolve) => setTimeout(resolve, 3000));
// 実際はここで認証結果を返す
return { success: true };
};
// ログインフォームのアクション(フォーム送信時に実行される)
const LoginFormAction = async (prevState: LoginFormStateType, formData: FormData): Promise<LoginFormStateType> => {
//名前とパスワードを取得
const name = formData.get("name");
const password = formData.get("password");
// ログイン処理を実行し、結果を取得
const response = await fetchLogin(name, password);
// ログイン結果を返す
return response;
};
export const LoginForm = () => {
// useActionStateフックを使用してフォームの状態、アクション、ローディング状態を管理
const [formState, formAction, isLoading] = useActionState(LoginFormAction, { success: false });
// 現在のフォーム状態をコンソールに出力(デバッグ用)
console.log(formState);
// ログイン結果メッセージを返す関数
const resultMessage = () => {
return formState.success ? "成功" : "エラー";
};
return (
<>
{/* フォーム要素。actionにformActionを指定してフォーム送信時の挙動を制御 */}
<form action={formAction}>
<div>
{/* ユーザー名入力フィールド */}
<label>Username: </label>
<input type="text" name="name" />
</div>
<div>
{/* パスワード入力フィールド */}
<label>Password: </label>
<input type="password" name="password" />
</div>
<button type="submit">submit</button> {/* 送信ボタン */}
</form>
{/* ローディング中は"loading..."を表示し、それ以外はログイン結果メッセージを表示 */}
{isLoading ? <div>loading...</div> : resultMessage()}
</>
);
};
コメントなし ver
import { useActionState } from "react";
type LoginFormStateType = {
success: boolean;
};
const fetchLogin = async (name, password): Promise<LoginFormStateType> => {
await new Promise((resolve) => setTimeout(resolve, 3000));
return { success: true };
};
const LoginFormAction = async (prevState: LoginFormStateType, formData: FormData): Promise<LoginFormStateType> => {
const name = formData.get("name");
const password = formData.get("password");
const response = await fetchLogin(name, password);
return response;
};
export const LoginForm = () => {
const [formState, formAction, isLoading] = useActionState(LoginFormAction, { success: false });
console.log(formState);
const resultMessage = () => {
return formState.success ? "成功" : "エラー";
};
return (
<>
<form action={formAction}>
<div>
<label>Username: </label>
<input type="text" name="name" />
</div>
<div>
<label>Password: </label>
<input type="password" name="password" />
</div>
<button type="submit">submit</button>
</form>
{isLoading ? <div>loading...</div> : resultMessage()}
</>
);
};
この例では、username, password を使用したログインフォームの処理を useActionState で管理しています。
手順
- useActionState には LoginFormAction(formAction で実行する関数)と formState の初期値を渡す
- form に入力して submit すると formAction が実行される
- LoginFormAction では前回の state と formData を受け取り処理をする
- formState に LoginFormAction の戻り値が代入される
- 2 ~ 4 の間に isLoading が true になるのでローディング表示をする
エラーハンドリング
今回はエラーハンドリングをしていませんが、LoginFormAction 内で catch したエラーを errorMessage に入力することで実装できます。
type LoginFormStateType = {
success: boolean;
errorMessage?: string; //LoginFormAction内で定義
};
useActionState の利点
-
状態管理の簡素化: 非同期アクションの状態管理が自動化され、コードがクリーンになります。
-
エラーハンドリングの改善: アクションのエラー状態を簡単に管理できます。
-
Server Actions との相性: JavaScript が読み込まれる前でもフォームが機能するため、ユーザー体験が向上します。
-
プログレッシブエンハンスメント:
permalink
オプションを使用することで、JavaScript が無効な環境でもフォームが機能します。
注意点
useActionState
に渡す関数は、最初の引数として前回のステート(または初期ステート)を受け取ります。- Server Actions を使用している場合、クライアントサイドの JavaScript が実行される前にフォームが操作可能になります。
まとめ
useActionState
は、React 19 で導入された非常に便利なフックです。フォーム処理や非同期アクションの状態管理を簡素化し、より効率的で読みやすいコードを書くことができます。特に Server Actions と組み合わせることで、パフォーマンスとユーザー体験の向上が期待できます。
参考資料